前言:以前学习java的时候,学习java的静态内部类,都只知道形式,可是却不知道,静态内部类是为了什么而出现,又是出现在哪些场景里面,导致写代码的时候,基本没有考虑到静态内部类,而最近在看<effective java>时和工作上都不约而同的出现了静态内部类,二者出现让我再次思考,java的静态内部类到底是干什么。
下面我并不会先说静态内部类的原理,优点等等东西。我会先从引起我思考的现象开始讲起。
下面是我们经常看到的代码,为了创建对象,给对象的每一个属性都给他set值,这个本身并没有问题,但当业务代码一长,这个类的属性越加越多,那么每一次创建对象,又给他每个属性赋值的代码就会显得又长又臭。业务代码本身已经够多,这个对象后面的初始化还要这么长的代码,就会让代码显得臃肿。
package meide;
public class Person {
private String name;
private String sex;
private double height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public static void main(String[] args) {
Person p = new Person();
p.setName("kris");
p.setSex("male");
p.setHeight(175.3);
}
}
因此,为了后面代码的简洁与高效,我又看到另一种代码:
package meide;
public class Person2 {
private String name;
private String sex;
private double height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public static builder init(){
return new builder();
}
public Person2(builder builder){
name = builder.getName();
sex = builder.getSex();
height = builder.getHeight();
}
public static class builder{
private String name;
private String sex;
private double height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public builder name(String name){
setName(name);
return this;
}
public builder sex(String sex){
setSex(sex);
return this;
}
public builder height(double height){
setHeight(height);
return this;
}
//1.先通过init创建builder
//2.再通过create返回对象
public Person2 create(){
return new Person2(this);
}
}
public static void main(String[] args) {
Person2 p2 = Person2.init().name("kris").sex("male").height(175.3).create();
System.out.println(p2.getName());
System.out.println(p2.getSex());
System.out.println(p2.getHeight());
}
}
从上面的代码我们可以看到创建对对象并且初始化的代码变得简洁了,这样面对众多业务代码的时候,就不显得那么臃肿了。
看完了上面的代码,首先,我们知道了静态内部类现实了构建器让代码简洁了,那现在我们思考一下内部类。
在《Think in java》中:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。--》内部类使用最明显的例子就是list的迭代器就是用内部类实现的。
/**
* Adapter to provide descending iterators via ListItr.previous
*/
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}
好,在看静态内部类前,我们先看一下非静态内部类,下面是我从别人那复制的代码:
public class OuterClass {
private String name ;
private int age;
/**省略getter和setter方法**/
public class InnerClass{
public InnerClass(){
name = "chenssy";
age = 23;
}
public void display(){
System.out.println("name:" + getName() +" ;age:" + getAge());
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.display();
}
}
--------------
Output:
name:chenssy ;age:23
在这里,我们看到非静态内部类的创建时需要外部类对象的引用的,而静态内部类却不需要外部类对象的引用,只需要外部类直接调静态内部类的。其实当我们仔细思考的时候,因为静态内部类用static修饰且是用public,首先说明静态内部类不是外部类私有的类,这样就不用先调外部类才能用这个内部类;其次,static修饰的内部类属于外部类的属性,只有一个内存空间,static修饰的属性与类相关而不与类的对象相关。且静态类只出现在内部类上。
static修饰符
static修饰符能够与属性、方法和内部类一起使用,表示静态的。类中的静态变量和静态方法能够与类名一起使用,不需要创建一个类的对象来访问该类的静态成员,所以,static修饰的变量又称作“类变量”。
static属性的内存分配
一个类中,一个static变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间。
static的变量是在类装载的时候就会被初始化,即,只要类被装载,不管是否使用了static变量,都会被初始化。
??那么有人会问:那么使用静态内部类的构建器使用web上,如果多人同时使用,会不会有线程安全问题呢?
首先会不会有线程安全问题,我们应该这么理解,线程安全问题是怎么发生,是因为当线程里面有静态变量时,因为多线程导致里面的静态变量因为共享同一内存而导致值被变化的原因。而在这种静态内部类实现的构建器里面,只要没有一个静态变量就不会有这种问题发生。此外:每个线程都有自己的线程栈,栈与线程同时创建,每一个虚拟机线程都有自己的程序计数器PC,在任何时刻,一个虚拟机线程只会执行一个方法的代码,这个方法称为该线程的当前方法,如果这个方法不是native的,程序计数器就保存虚拟机正在执行的字节码指令的地址。线程调用方法的时候会创建栈帧,用于保存局部变量表和操作数栈以及指向该类常量池的引用
静态方法虽然是同一个方法,但是不同线程在调用,程序计数器的值是不一样的,操作这两个线程不会相互影响(假设不存在访问共享变量的情况)
好了,经过上面的过程,我们明白了静态内部类的优点:
1.静态内部类不依赖外部类的对象实例,与外部类有关
2.使用静态内部类独立的完成接口的实现